import hashlib
import uuid
from typing import Union, Any
import json
import re
def deterministic_uuid(content: Union[str, bytes]) -> str:
    """Creates deterministic UUID on hash value of string or byte content.

    Args:
        content: String or byte representation of data.

    Returns:
        UUID of the content.
    """
    if isinstance(content, str):
        content_bytes = content.encode("utf-8")
    elif isinstance(content, bytes):
        content_bytes = content
    else:
        raise ValueError(f"Content type {type(content)} not supported !")

    hash_object = hashlib.sha256(content_bytes)
    hash_hex = hash_object.hexdigest()
    namespace = uuid.UUID("00000000-0000-0000-0000-000000000000")
    content_uuid = str(uuid.uuid5(namespace, hash_hex))

    return content_uuid

def _parse_llm_response(response: str, default_value: Any = None) -> Any:
    """
    解析大模型返回的JSON格式响应
    
    Args:
        response (str): 大模型返回的响应字符串
        default_value (Any, optional): 解析失败时的默认返回值
        
    Returns:
        Any: 解析后的Python对象，解析失败则返回default_value
    """
    try:
        if not response:
            raise ValueError("LLM返回空响应")
        # 1. 尝试直接解析
        try:
            return json.loads(response)
        except json.JSONDecodeError:
            pass
            
        # 2. 尝试提取JSON部分
        import re
        json_pattern = r'(\{[\s\S]*\}|\[[\s\S]*\])'  # 匹配包括换行符在内的所有JSON内容
        json_match = re.search(json_pattern, response)
        
        if (json_match):
            try:
                return json.loads(json_match.group())
            except json.JSONDecodeError:
                pass
        
        # 3. 清理常见的格式问题
        cleaned_response = response.strip()
        # 移除可能的markdown代码块标记
        if cleaned_response.startswith('```json'):
            cleaned_response = cleaned_response[7:]
        if cleaned_response.endswith('```'):
            cleaned_response = cleaned_response[:-3]
            
        cleaned_response = cleaned_response.strip()
        
        try:
            return json.loads(cleaned_response)
        except json.JSONDecodeError as e:
            print(f"JSON parse error: {str(e)}")
            print(f"Raw response: {response}")
            return default_value
            
    except Exception as e:
        print(f"解析LLM响应时发生错误: {str(e)}")
        print(f"原始响应: {response}")
        return default_value
def extract_sql(llm_response: str) -> str:
    """
    Example:
    ```python
    vn.extract_sql("Here's the SQL query in a code block: ```sql\nSELECT * FROM customers\n```")
    ```

    Extracts the SQL query from the LLM response. This is useful in case the LLM response contains other information besides the SQL query.
    Override this function if your LLM responses need custom extraction logic.

    Args:
        llm_response (str): The LLM response.

    Returns:
        str: The extracted SQL query.
    """

    # If the llm_response contains a CTE (with clause), extract the last sql between WITH and ;
    sqls = re.findall(r"\bWITH\b .*?;", llm_response, re.DOTALL)
    if sqls:
        sql = sqls[-1]
        return sql

    # If the llm_response is not markdown formatted, extract last sql by finding select and ; in the response
    sqls = re.findall(r"SELECT.*?;", llm_response, re.DOTALL)
    if sqls:
        sql = sqls[-1]
        return sql

    # If the llm_response contains a markdown code block, with or without the sql tag, extract the last sql from it
    sqls = re.findall(r"```sql\n(.*)```", llm_response, re.DOTALL)
    if sqls:
        sql = sqls[-1]
        return sql

    sqls = re.findall(r"```(.*)```", llm_response, re.DOTALL)
    if sqls:
        sql = sqls[-1]
        return sql

    return llm_response